#ifndef __UDP_SERVER_HPP__
#define __UDP_SERVER_HPP__

#include"Log.hpp"
#include"InetAddr.hpp"
#include"Common.hpp"
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include<string>
#include<cstring>
#include <netinet/in.h>
#include<iostream>

using namespace LogModule;

class UdpServer
{
public:
    UdpServer(uint16_t port)
    :_addr(port)
    ,_sockfd(-1)
    ,_isrunning(false)
    {}

    void InitServer()
    {
        //1.创建socket文件
        _sockfd=::socket(AF_INET, SOCK_DGRAM,0);//什么族，什么类型的传输协议
        if(_sockfd<0)
        {
            LOG(LogLevel::FATAL)<<"socket"<<strerror(errno);
            Die(SOCKET_ERR);
        }

        LOG(LogLevel::INFO)<<"socket success,_socket is"<<_sockfd;

        int n=::bind(_sockfd,_addr.NetAddr(),_addr.NetAddrLen());
        if(n<0)
        {
            LOG(LogLevel::FATAL)<<"bind"<<strerror(errno);
            Die(BIND_ERR);
        }
        LOG(LogLevel::INFO)<<"bind success";
    }
    //服务器接受东西之后日志打印是谁发的，然后再回发
    void Start()
    {
        _isrunning=true;
        while(true)
        {
            char inbuffer[1024];
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            //recvfrom的大小必须用socklen_t*   sendto可以不是socklen_t
            int n=::recvfrom(_sockfd,inbuffer,sizeof(inbuffer)-1,0,CONV(&peer),&len);
            if(n>0)
            {
                InetAddr cli(peer);//构造这个对象是为了把网络字节序改成主机字节序
                inbuffer[n]=0;
                
                std::string clientinfo=cli.Ip()+" : "+std::to_string(cli.Port())+\
                                  " # "+inbuffer;
                LOG(LogLevel::DEBUG)<<clientinfo;

                std::string echo_string="echo# ";
                echo_string+=inbuffer;
                ::sendto(_sockfd,echo_string.c_str(),echo_string.size(),0,CONV(&peer),len);


            }
            
        }
        _isrunning=false;
    }

    ~UdpServer()
    {
        if(_sockfd!=-1)
        {
            ::close(_sockfd);
        }
    }




private:
    int _sockfd;
    InetAddr _addr;//服务端设置IP为0,即不关心IP，只要发来直接接收
    bool _isrunning;

};


#endif